package com.stable.actor.network;

import lombok.extern.slf4j.Slf4j;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * TCP连接池 - 内部使用
 */
@Slf4j
class TcpConnectionPool {
    private final String host;
    private final int port;
    private final ConcurrentLinkedQueue<Socket> pool = new ConcurrentLinkedQueue<>();
    private final int maxSize = 10;
    private final int connectTimeout = 5000;
    private final int readTimeout = 30000;

    public TcpConnectionPool(String host, int port) {
        this.host = host;
        this.port = port;
        // 预热连接
        preheatConnections();
    }

    private void preheatConnections() {
        for (int i = 0; i < 2; i++) {
            try {
                Socket socket = createSocket();
                pool.offer(socket);
            } catch (IOException e) {
                System.err.println("预热连接失败: " + e.getMessage());
            }
        }
    }

    public byte[] sendSync(byte[] request) throws IOException {
        Socket socket = null;
        try {
            socket = borrowSocket();
            return doSend(socket, request);
        } finally {
            returnSocket(socket);
        }
    }

    private Socket borrowSocket() throws IOException {
        Socket socket = pool.poll();
        if (socket != null && !socket.isClosed() && socket.isConnected()) {
            return socket;
        }
        return createSocket();
    }

    private void returnSocket(Socket socket) {
        if (socket != null && !socket.isClosed() && socket.isConnected() && pool.size() < maxSize) {
            pool.offer(socket);
        } else {
            closeSocket(socket);
        }
    }

    private Socket createSocket() throws IOException {
        Socket socket = new Socket();
        socket.setSoTimeout(readTimeout);
        socket.setTcpNoDelay(true);

        // 添加连接重试逻辑

        while(true) {
            try {
                log.info("正在尝试连接: " + host + ":" + port);
                socket.connect(new InetSocketAddress(host, port), connectTimeout);
                System.out.println("✅ 连接成功: " + host + ":" + port);
                return socket;
            } catch (IOException e) {
                System.out.println("⚠️ 连接失败，再次重试  " + e.getMessage());
                try {
                    Thread.sleep(1000); // 等待1秒后重试
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new IOException("连接被中断", ie);
                }
            }
        }

    }

    private byte[] doSend(Socket socket, byte[] request) throws IOException {
        OutputStream out = socket.getOutputStream();
        InputStream in = socket.getInputStream();

        // 发送请求
        out.write(encodeWithLength(request));
        out.flush();

        // 读取响应
        return readWithLength(in);
    }

    private byte[] encodeWithLength(byte[] data) {
        byte[] lengthBytes = ByteBuffer.allocate(4).putInt(data.length).array();
        byte[] result = new byte[4 + data.length];
        System.arraycopy(lengthBytes, 0, result, 0, 4);
        System.arraycopy(data, 0, result, 4, data.length);
        return result;
    }

    private byte[] readWithLength(InputStream in) throws IOException {
        // 读取长度头
        byte[] lengthBytes = new byte[4];
        readFully(in, lengthBytes);
        int length = ByteBuffer.wrap(lengthBytes).getInt();

        // 读取数据体
        byte[] data = new byte[length];
        readFully(in, data);
        return data;
    }

    private void readFully(InputStream in, byte[] buffer) throws IOException {
        int totalRead = 0;
        while (totalRead < buffer.length) {
            int read = in.read(buffer, totalRead, buffer.length - totalRead);
            if (read == -1) {
                throw new EOFException("连接被对端关闭");
            }
            totalRead += read;
        }
    }

    private void closeSocket(Socket socket) {
        try {
            if (socket != null) {
                socket.close();
            }
        } catch (IOException e) {
            // 忽略关闭异常
        }
    }

    public void shutdown() {
        Socket socket;
        while ((socket = pool.poll()) != null) {
            closeSocket(socket);
        }
    }
}
